/*
Copyright (c) 2012, Weikexin eeplat.com
Released under the MIT license.
http://www.opensource.org/licenses/mit-license.php
 */
package com.eeplat.social.openapi.renren;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.eeplat.social.openapi.callback.GlobalConfig;
import com.eeplat.social.openapi.http.BaseAuth;
import com.eeplat.social.openapi.http.HttpClient;
import com.eeplat.social.openapi.http.HttpURLUtils;
import com.eeplat.social.openapi.http.OpenApiException;
import com.eeplat.social.openapi.http.PostParameter;
import com.eeplat.social.openapi.http.Response;

/**
 * Wrapper Redirect Url Helper Class for RenRen
 * 
 * @author Weikexin
 * 
 */
public class AuthRenRen extends BaseAuth {

	public static final String BASE = "http://api.renren.com/restserver.do";

	public static final String AUTH = "https://graph.renren.com/oauth/authorize";

	public static final String TOKEN = "https://graph.renren.com/oauth/token";

	/**
	 * RenRen's redirectUrl is combination of response_type,display,client_id
	 * and redirect_uri.
	 * 
	 * @param redirectUri
	 * @return wrapped uri
	 */
	public String wrappRedirectUri() {

		StringBuffer sb = new StringBuffer(AUTH);
		sb.append("?response_type=code&display=page&client_id=")
				.append(GlobalConfig.getValue("renrenAppID"))
				.append("&redirect_uri=")
				.append(GlobalConfig.getCallBack("renren.cb"));
		return sb.toString();
	}

	public String wrappAuthCodeUri(String authCode) {

		StringBuffer sb = new StringBuffer(TOKEN);
		sb.append("?grant_type=authorization_code&client_id=")
				.append(GlobalConfig.getValue("renrenApiKey"))
				.append("&client_secret=")
				.append(GlobalConfig.getValue("renrenApiSecret"))
				.append("&code=").append(authCode).append("&grant_type=")
				.append("authorization_code").append("&redirect_uri=")
				.append(GlobalConfig.getValue("renren.cb"));
		return sb.toString();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.eeplat.social.openapi.qq.BaseURIUtil#wrappAccessTokenUri(java.lang
	 * .String)
	 */

	public String wrappAccessTokenUri(String accessToken) {

		StringBuffer sb = new StringBuffer(BASE);
		sb.append("?access_token=").append(accessToken);
		return sb.toString();
	}

	public String getAccessToken(String oauthCode) throws OpenApiException {

		String authUri = wrappAuthCodeUri(oauthCode);

		HttpClient http = new HttpClient();
		Response res;
		try {
			res = http.httpRequest(authUri, null, "GET");
			String ret = res.asString();
			Map<String, Object> data = objectMapper.readValue(ret, Map.class);
			return (String) data.get("access_token");
		} catch (Exception e) {
			throw new OpenApiException(e);
		}
	}

	/**
	 * 使用Access Token来发送新鲜事
	 * 
	 * @param accessToken
	 * @return
	 * @throws OpenApiException
	 */
	public Boolean publishFeed(String accessToken, String msg)
			throws OpenApiException {
		String getOpenIdUri = wrappAccessTokenUri(accessToken);
		HttpClient http = new HttpClient();

		Map<String, Object> data;
		try {
			Map<String, String> paramMap = new HashMap<String, String>();
			paramMap.put("v", "1.0");
			paramMap.put("method", "feed.publishFeed");
			paramMap.put("name", "我在城市缘等你");
			paramMap.put("description", "没人陪我聊天，谁有空？");
			paramMap.put("url", "http://www.thenicecity.com");
			paramMap.put("action_name", "城市缘");
			paramMap.put("action_link", "http://www.thenicecity.com");

			paramMap.put("message", msg);
			paramMap.put("access_token", accessToken);
			paramMap.put("format", "JSON");

			String sig = this.getSignature(paramMap,
					GlobalConfig.getValue("renrenApiSecret"));
			paramMap.put("sig", sig);

			List<PostParameter> paramList = new ArrayList<PostParameter>(
					paramMap.size());
			for (Map.Entry<String, String> param : paramMap.entrySet()) {
				paramList.add(new PostParameter(param.getKey(), param
						.getValue()));
			}
			PostParameter[] strArray = new PostParameter[paramList.size()];
			paramList.toArray(strArray);

			// Response res = http.post(getOpenIdUri,strArray);
			String ret = HttpURLUtils.doPost(getOpenIdUri, paramMap);
			// callback( {"client_id":"YOUR_APPID","openid":"YOUR_OPENID"} );
			data = objectMapper.readValue(ret, Map.class);
			if (data.get("post_id") != null) {
				return (Integer) (data.get("post_id")) > 0;
			} else {
				throw new OpenApiException((String) data.get("error_msg"));
			}

		} catch (Exception e) {
			throw new OpenApiException(e);
		}
	}

	/**
	 * 使用Access Token来获取用户的UserID
	 * 
	 * @param accessToken
	 * @return
	 * @throws OpenApiException
	 */
	public String getUserID(String accessToken) throws OpenApiException {
		String getOpenIdUri = wrappAccessTokenUri(accessToken);
		HttpClient http = new HttpClient();

		Map<String, Object> data;
		try {
			long time = System.currentTimeMillis();
			String strTime = URLEncoder.encode(String.valueOf(time));

			Map<String, String> paramMap = new HashMap<String, String>();
			paramMap.put("v", "1.0");
			paramMap.put("method", "users.getLoggedInUser");
			paramMap.put("call_id", "strTime");
			paramMap.put("access_token", accessToken);
			paramMap.put("format", "JSON");

			String sig = this.getSignature(paramMap,
					GlobalConfig.getValue("renrenApiSecret"));
			paramMap.put("sig", sig);

			List<PostParameter> paramList = new ArrayList<PostParameter>(
					paramMap.size());
			for (Map.Entry<String, String> param : paramMap.entrySet()) {
				paramList.add(new PostParameter(param.getKey(), param
						.getValue()));
			}
			PostParameter[] strArray = new PostParameter[paramList.size()];
			paramList.toArray(strArray);

			// Response res = http.post(getOpenIdUri,strArray);
			String ret = HttpURLUtils.doPost(getOpenIdUri, paramMap);
			// callback( {"client_id":"YOUR_APPID","openid":"YOUR_OPENID"} );
			data = objectMapper.readValue(ret, Map.class);
			if (data.get("uid") != null) {
				return String.valueOf(data.get("uid"));
			} else {
				throw new OpenApiException((String) data.get("error_msg"));
			}

		} catch (Exception e) {
			throw new OpenApiException(e);
		}
	}

	private String getSignature(Map<String, String> paramMap, String secret) {
		List<String> paramList = new ArrayList<String>(paramMap.size());
		// 1、参数格式化
		for (Map.Entry<String, String> param : paramMap.entrySet()) {
			paramList.add(param.getKey() + "=" + param.getValue());
		}
		// 2、排序并拼接成一个字符串
		Collections.sort(paramList);
		StringBuffer buffer = new StringBuffer();
		for (String param : paramList) {
			buffer.append(param);
		}
		// 3、追加script key
		buffer.append(secret);
		// 4、将拼好的字符串转成MD5值
		try {
			java.security.MessageDigest md = java.security.MessageDigest
					.getInstance("MD5");
			StringBuffer result = new StringBuffer();
			try {
				for (byte b : md.digest(buffer.toString().getBytes("UTF-8"))) {
					result.append(Integer.toHexString((b & 0xf0) >>> 4));
					result.append(Integer.toHexString(b & 0x0f));
				}
			} catch (UnsupportedEncodingException e) {
				for (byte b : md.digest(buffer.toString().getBytes())) {
					result.append(Integer.toHexString((b & 0xf0) >>> 4));
					result.append(Integer.toHexString(b & 0x0f));
				}
			}
			return result.toString();
		} catch (java.security.NoSuchAlgorithmException ex) {
			log.error("get getSignature fail...", ex);
		}
		return null;
	}

}
